
# Python函数编程

# 定义一个函数
# 函数代码块以 def 关键词开头，后接函数标识符名称和圆括号 ()。
# 任何传入参数和自变量必须放在圆括号中间，圆括号之间可以用于定义参数。
# 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
# 函数内容以冒号起始，并且缩进。
# return [表达式] 结束函数，选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
# 格式如下：
# def 函数名（参数列表）:
#     函数体


def hello():
    print("这是一个函数")

# 调用函数
hello()


# 加参函数  在 python 中，类型属于对象，变量是没有类型的：
def area(width,height):
    return width*height

print(area(3,4))




# 可更改(mutable)与不可更改(immutable)对象
# 在 python 中，strings, tuples, 和 numbers 是不可更改的对象，而 list,dict,tuple 等则是可以修改的对象。
# 不可变类型：变量赋值 a=5 后再赋值 a=10，这里实际是新生成一个 int 值对象 10，再让 a 指向它，而 5 被丢弃，不是改变a的值，相当于新生成了a。
# 可变类型：变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改，本身la没有动，只是其内部的一部分值被修改了。
# python 函数的参数传递：
# 不可变类型：类似 c++ 的值传递，如 整数、字符串、元组。如fun（a），传递的只是a的值，没有影响a对象本身。比如在 fun（a）内部修改 a 的值，只是修改另一个复制的对象，不会影响 a 本身。
# 可变类型：类似 c++ 的引用传递，如 列表，字典。如 fun（la），则是将 la 真正的传过去，修改后fun外部的la也会受影响
# python 中一切都是对象，严格意义我们不能说值传递还是引用传递，我们应该说传不可变对象和传可变对象。


# python 传不可变对象
# 实例中有 int 对象 2，指向它的变量是 b，在传递给 ChangeInt 函数时
# 按传值的方式复制了变量 b，a 和 b 都指向了同一个 Int 对象，在 a=10 时，则新生成一个 int 值对象 10，并让 a 指向它。
def change(a):
    a = 12
b = 2
change(b)
print(b)  # 2


# 传可变对象
list = [1,2,3,4,5,6]
def changeList(a):
    a[2] = 9
changeList(list)
print(list) # [1, 2, 9, 4, 5, 6]




# 默认参数
# 调用函数时，如果没有传递参数，则会使用默认参数。以下实例中如果没有传入 age 参数，则使用默认值：

def printinfo(name, age=35):
    "打印任何传入的字符串"
    print("名字: ", name)
    print("年龄: ", age)
    return

printinfo(age=50, name="zsc")
print("------------------------")
printinfo(name="zsc")


# ----------------------------------------------------------------------------------


# 不定长参数
# 你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数，和上述 2 种参数不同，声明时不会命名。基本语法如下：
# def functionname([formal_args,] *var_args_tuple ):
#    "函数_文档字符串"
#    function_suite
#    return [expression]

# 加了星号 * 的参数会以元组(tuple)的形式导入，存放所有未命名的变量参数。
# 可写函数说明
def printinfo(arg1, *vartuple):
    print("输出: ")
    print(arg1)
    print(vartuple)

printinfo(70, 60, 50)

# 输出:
# 70
# (60, 50)


# 加了两个星号 ** 的参数会以字典的形式导入。
def printinfo(arg1, **vardict):
    print("输出: ")
    print(arg1)
    print(vardict)

printinfo(1, a=2, b=3)

# 以上实例输出结果：
# 输出:
# 1
# {'a': 2, 'b': 3}


# 如果单独出现星号 * 后的参数必须用关键字传入。

# ----------------------------------------------------------------------------------

# 匿名函数
# python 使用 lambda 来创建匿名函数。 跟Java中的lambda截然不同，不要混淆
# lambda的主体是一个表达式，而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
# lambda 函数拥有自己的命名空间，且不能访问自己参数列表之外或全局命名空间里的参数。
# 虽然lambda函数看起来只能写一行，却不等同于C或C++的内联函数，后者的目的是调用小函数时不占用栈内存从而增加运行效率。

sum = lambda arg1, arg2: arg1 + arg2

# 调用sum函数
print("相加后的值为 : ", sum(10, 20))
print("相加后的值为 : ", sum(20, 20))
